#include "CDal.h"
#include <iostream>
#include <algorithm>
#include "core/lib/sqlite/sqlite3.h"
#include "CDalRecord.h"

CDal::CDal()
{

}

CDal::~CDal()
{
  //dtor
}

/** @brief connect
  *
  * @todo: document this function
  */
sqlite3* CDal::open(const char *db)
{
  sqlite3* connection;
  int responseCode = sqlite3_open(db, &connection);
  if( responseCode != SQLITE_OK)
  {
    std::cout << "Can't open database: " << sqlite3_errmsg(connection) << std::endl;
    sqlite3_close(connection);
  }
  std::cout << "SQLite: Connected to " << db << std::endl;
  return connection;
}

void CDal::close(const char *db)
{
  std::string name = db;
  sqlite3_close(mConnection[name]);
  std::cout << "SQLite: Disconnected to " << db << std::endl;
}

sqlite3* CDal::getConnection(const char *db)
{
  std::string name = db;
  std::cout << "Getting Connection: " << db << std::endl;

  if ( mConnection.find(name) != mConnection.end() )
  {
    std::cout << "Connection Found" << std::endl;
    return mConnection[name];
  }

  // Lazy init
  else
  {
    std::cout << "Connection Not Found!. Initializing" << db << std::endl;
    mConnection[name] = open(name.c_str());
    return mConnection[name];
  }
}

/** @brief insertSql
  *
  * @todo: document this function
  */
bool CDal::insertSql(const char *db, const char *sql)
{
  sqlite3 *pConnection = getConnection(db);
  sqlite3_stmt *pStatement;
  sqlite3_prepare_v2(pConnection, sql, strlen(sql), &pStatement, 0);

  std::cout << "\n-----\nSQLite: " << sql << "\n-----" << std::endl;

  int response_code = sqlite3_step(pStatement);
  bool result;
  if (response_code == SQLITE_DONE)
  {
    result = true;
  }
  else
  {
    std::cout << "SQLite: ERROR " << response_code << ": ";
    std::cout << sqlite3_errmsg(pConnection) << std:: endl;

    result = false;
  }
  sqlite3_finalize(pStatement); // Close statement

  return result;
}

int CDal::getLastInsertId(const char *db)
{
  return sqlite3_last_insert_rowid(getConnection(db));
}

/** @brief selectSql
  *
  * @todo: document this function
  */
CDalRecord* CDal::selectSql(const char *db, const char *sql)
{
  sqlite3 *pConnection = getConnection(db);
  sqlite3_stmt *pStatement;
  sqlite3_prepare_v2(pConnection, sql, strlen(sql), &pStatement, 0);

  std::cout << "\n-----\nSQLite: " << sql << "\n-----" << std::endl;

  CDalRecord *pResult = new CDalRecord(pStatement);
  return pResult;
}

/** @brief escape
  *
  * @todo: document this function
  */
std::string CDal::escape(const std::string &base, char find)
{
  std::string result = base;
  result.erase(
    remove(result.begin(), result.end(), find),
    result.end()
  );

  return result;
}



std::map <std::string, sqlite3*> CDal::mConnection;

